#pragma once
#include <memory>
#include "../Server.hpp"
#include "Util.hpp"
#include "HttpRequest.hpp"
#include "HttpResponse.hpp"
#include "HttpContext.hpp"
#define DEFALT_TIMEOUT 10
class HttpServer
{
private:
    using Handler = std::function<void(const HttpRequest &, HttpResponse *)>;
    using Handlers = std::vector<std::pair<std::regex, Handler>>;
    Handlers _get_route;
    Handlers _post_route;
    Handlers _put_route;
    Handlers _delete_route;
    std::string _basedir;
    TCPServer _server;

    void OnClosed(const PtrConnection &conn)
    {
        std::cout << "Closed Connection: " << conn.get() << std::endl;
    }
    // 设置上下文
    void OnConnected(const PtrConnection &conn)
    {
        conn->SetContext(HttpContext());
        std::cout << "New Connection: " << conn.get() << std::endl;
    }
    // 缓冲区数据解析与处理
    void OnMessage(const PtrConnection &conn, Buffer *buf)
    {
        while (buf->ReadAbleSize() > 0)
        {
            // 获取上下文
            HttpContext *context = conn->GetContext()->Get<HttpContext>();
            // HttpRequest数据解析
            context->RecvHttpRequest(buf);
            HttpRequest &req = context->Request();
            HttpResponse resp(context->RespStatu());
            if (context->RespStatu() >= 400)
            {
                // 进行错误响应，关闭连接
                ErrorHandler(req, &resp);
                WriteResponse(conn, req, resp);
                buf->ConfirmReadSize(buf->ReadAbleSize());
                conn->Shutdown();
                return;
            }
            if (context->RecvStatu() != RECV_HTTP_OVER)
            {
                // 当前请求还没有接收完整，退出，等新数据到来再重新继续处理
                return;
            }
            // 请求路由与业务处理
            Route(req, &resp);
            // HttpResponse响应
            WriteResponse(conn, req, resp);
            // 重置上下文
            context->ReSet();
            // 根据长短链接判断关闭连接或继续处理
            if (resp.Close())
                conn->Shutdown();
        }
    }
    // 路由
    void Route(HttpRequest &req, HttpResponse *resp)
    {
        if (IsFile(req))
        {
            FileHandler(req, resp);
            return;
        }
        if (req._method == "GET" || req._method == "HEAD")
        {
            FunctionHandler(req, resp, _get_route);
            return;
        }
        else if (req._method == "POST")
        {
            FunctionHandler(req, resp, _post_route);
            return;
        }
        else if (req._method == "PUT")
        {
            FunctionHandler(req, resp, _put_route);
            return;
        }
        else if (req._method == "DELETE")
        {
            FunctionHandler(req, resp, _delete_route);
            return;
        }
        // 405 Method Not Allowed
        resp->_statu = 405;
    }
    // 判断是否为静态资源
    bool IsFile(const HttpRequest &req)
    {
        // 必须设置了静态资源根目录
        if (_basedir.empty())
        {
            return false;
        }
        // 请求方法，必须是GET / HEAD请求方法
        if (req._method != "GET" && req._method != "HEAD")
        {
            return false;
        }
        // 请求的资源路径必须是一个合法路径
        if (Util::IsValidPath(req._path) == false)
        {
            return false;
        }
        // 转换为绝对路径
        std::string req_path = _basedir + req._path;
        // 请求的资源必须存在,且是一个普通文件
        // 有一种请求比较特殊 -- 目录：/, /image/， 这种情况给后边默认追加一个 index.html
        if (req._path.back() == '/')
        {
            req_path += "index.html";
        }
        if (!Util::IsRegular(req_path))
        {
            return false;
        }
        return true;
    }
    // 静态资源请求处理
    void FileHandler(const HttpRequest &req, HttpResponse *resp)
    {
        std::string req_path = _basedir + req._path;
        if (req._path.back() == '/')
        {
            req_path += "index.html";
        }
        if (!Util::ReadFile(req_path, &resp->_body))
            return;
        std::string mime = Util::ExtMine(req_path);
        resp->SetHeader("Content-Type", mime);
    }
    // 功能性请求处理
    void FunctionHandler(HttpRequest &req, HttpResponse *resp, Handlers &handlers)
    {
        for (auto &handler : handlers)
        {
            const std::regex &re = handler.first;
            const Handler &functor = handler.second;
            if (std::regex_match(req._path, req._matches, re))
            {
                functor(req, resp);
                return;
            }
        }
        resp->_statu = 404;
    }
    // 错误请求响应
    void ErrorHandler(const HttpRequest &req, HttpResponse *resp)
    {
        // 组织一个错误展示页面
        std::string body;
        body += "<html>";
        body += "<head>";
        body += "<meta http-equiv='Content-Type' content='text/html;charset=utf-8'>";
        body += "</head>";
        body += "<body>";
        body += "<h1>";
        body += std::to_string(resp->_statu);
        body += " ";
        body += Util::StatuDesc(resp->_statu);
        body += "</h1>";
        body += "</body>";
        body += "</html>";
        // 将页面数据，当作响应正文，放入rsp中
        resp->SetContent(body, "text/html");
    }
    // 设置Response
    void WriteResponse(const PtrConnection &conn, const HttpRequest &req, HttpResponse &resp)
    {
        // 完善头部字段
        if (req.Close())
        {
            resp.SetHeader("Connection", "close");
        }
        else
        {
            resp.SetHeader("Connection", "keep-alive");
        }
        if (resp._body.empty() == false && resp.HasHeader("Content-Length") == false)
        {
            resp.SetHeader("Content-Length", std::to_string(resp._body.size()));
        }
        if (resp._body.empty() == false && resp.HasHeader("Content-Type") == false)
        {
            resp.SetHeader("Content-Type", "application/octet-stream");
        }
        if (resp._redirect_flag == true)
        {
            resp.SetHeader("Location", resp._redirect_url);
        }
        // 组织resp内容
        std::stringstream respStr;
        respStr << req._version << " " << std::to_string(resp._statu) << " " << Util::StatuDesc(resp._statu) << "\r\n";
        for (auto [k, v] : resp._headers)
        {
            respStr << k << ": " << v << "\r\n";
        }
        respStr << "\r\n";
        respStr << resp._body;
        // 发送数据
        conn->Send(respStr.str().c_str(), respStr.str().size());
    }

public:
    HttpServer(int port, int timeout = DEFALT_TIMEOUT) : _server(port)
    {
        _server.EnableInactiveRelease(timeout);
        _server.SetConnectedCallback(std::bind(&HttpServer::OnConnected, this, std::placeholders::_1));
        _server.SetMessageCallback(std::bind(&HttpServer::OnMessage, this, std::placeholders::_1, std::placeholders::_2));
        _server.SetClosedCallback(std::bind(&HttpServer::OnClosed, this, std::placeholders::_1));
    }
    ~HttpServer() {}
    void SetBasedir(const std::string &path)
    {
        assert(Util::IsDirectory(path));
        _basedir = path;
    }
    void SetGetMethod(const std::string &pattern, const Handler &handler)
    {
        _get_route.push_back(std::make_pair(std::regex(pattern), handler));
    }
    void SetPostMethod(const std::string &pattern, const Handler &handler)
    {
        _post_route.push_back(std::make_pair(std::regex(pattern), handler));
    }
    void SetPutMethod(const std::string &pattern, const Handler &handler)
    {
        _put_route.push_back(std::make_pair(std::regex(pattern), handler));
    }
    void SetDeleteMethod(const std::string &pattern, const Handler &handler)
    {
        _delete_route.push_back(std::make_pair(std::regex(pattern), handler));
    }
    void SetThreadCount(int count) { _server.SetThreadCount(count); }
    void Listen() { _server.Start(); }
};